#include <SRL/Utils/Core.h>

namespace srl {

	srl::Vector<float> glToScreen(const float x, const float y, const float z) {
		return glToScreen(srl::Vector<float>(x,y,z));
	} 
	srl::Vector<float> glToScreen(const srl::Vector<float>& v)
	{
	   
		// Get the matrices and viewport
		float modelView[16];
		float projection[16];
		float viewport[4];
		float depthRange[2];

		glGetFloatv(GL_MODELVIEW_MATRIX, modelView);
		glGetFloatv(GL_PROJECTION_MATRIX, projection);
		glGetFloatv(GL_VIEWPORT, viewport);
		glGetFloatv(GL_DEPTH_RANGE, depthRange);

		// Compose the matrices into a single row-major transformation
		srl::Matrix<float> T;
		int r, c, i;
		for (r = 0; r < 4; ++r) {
			for (c = 0; c < 4; ++c) {
			  T[r][c] = 0.0;
			  for (i = 0; i < 4; ++i) {
				 T[r][c] += projection[r + i * 4] * modelView[i + c * 4];
			  }
			}
		} 

		srl::Vector<float> result;
		for(r = 0; r < 4; ++r) {
			result[r] = T[r].dot(v);
		}

		// Homogeneous divide
		const double rhw = 1 / result.w;

		return srl::Vector<float>(
		(1 + result.x * rhw) * viewport[2] / 2 + viewport[0],
		(1 - result.y * rhw) * viewport[3] / 2 + viewport[1],
		(result.z * rhw) * (depthRange[1] - depthRange[0]) + depthRange[0],
		rhw);
	}


 	srl::Texture Load(std::string url, srl::Texture* tex) {
   		GLuint id;
   		id = SOIL_load_OGL_texture(url.c_str(), SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y);
   		
    	if(!(glIsTexture(id)==GL_TRUE))
    		printf("<Error> Id passed to Texture Constructor is not a texture id \n");
   		else {
    		//Log::__Singleton() << "[Info]  " << "Texture \"" << url << " loaded\n";
    		
			if(tex == NULL) {
				srl::Texture retTex; retTex.mId = id;
				return retTex;
			}
			else
				tex->mId = id;
    	}
    }
    
    
    void Send(int flags) {
    	if(srl::Program::Current != 0) {
    	
    	// Light
    	if(flags & SRL_LIGHT)
    		srl::Program::Current->Uniform("srlLightEn", 1);
    	else if(flags & SRL_NO_LIGHT)
    		srl::Program::Current->Uniform("srlLightEn", 0);
    	
    	// Color
    	if(flags & SRL_COLOR)
    		srl::Program::Current->Uniform("srlColorEn", 1);
    	else if(flags & SRL_NO_COLOR)
    		srl::Program::Current->Uniform("srlColorEn", 0);
    	
    	// Diffuse Tex
    	if(flags & SRL_DIFFUSE)
    		srl::Program::Current->Uniform("srlDiffuseEnabled", 1);
    	else if(flags & SRL_NO_DIFFUSE)
    		srl::Program::Current->Uniform("srlDiffuseEnabled", 0);
    	
    	// Parallax
    	if(flags & SRL_PARALLAX)
    		srl::Program::Current->Uniform("srlParallaxEnabled", 1);
    	else if(flags & SRL_NO_PARALLAX)
    		srl::Program::Current->Uniform("srlParallaxEnabled", 0);
    		
    	// Scale
    	if(flags & SRL_REPEAT)
    		srl::Program::Current->Uniform("srlRepeatType", 2);
    	else if(flags & SRL_ONCE)
    		srl::Program::Current->Uniform("srlRepeatType", 1);
    	else if(flags & SRL_SCALE)
    		srl::Program::Current->Uniform("srlRepeatType", 0);
    	
    	if(flags & SRL_NORMAL)
    		srl::Program::Current->Uniform("srlNormalMapping", 1);
    	else if(flags & SRL_NO_NORMAL)
    		srl::Program::Current->Uniform("srlNormalMapping", 0);
    	
    	}
    }

};
